package pl.enigmatic.parser.xml;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

import pl.enigmatic.util.Reflection;


@SuppressWarnings("rawtypes")
public final class CollectionParser<X> extends Parser<Collection> {

	/** a collection of parsers maintained to keep the ones already created */
	private static HashMap<String, CollectionParser> parsers = new HashMap<String, CollectionParser>();

	protected static <X> CollectionParser createCollectionParser(final Class<X> clazz) {
		final String name = clazz.getName();
		if (!parsers.containsKey(name)) {
			final CollectionParser<X> parser = new CollectionParser<X>(clazz);
			parsers.put(name, parser);
			return parser;
		}
		return parsers.get(name);
	}

	protected static CollectionParser createCollectionParser(final String clazz) {
		if (!parsers.containsKey(clazz)) {
			return createCollectionParser(Reflection.classForName(clazz));
		} else {
			return parsers.get(clazz);
		}
	}

	private final Parser<X> parser;

	CollectionParser(final Parser<X> parser) {
		super(Collection.class, false);
		this.parser = parser;
	}

	CollectionParser(final Class<X> cls) {
		this(createParser(cls));
	}

	public final CollectionParser<X> copy(final Parser<X> custom) {
		if (custom == parser || custom == null) {
			return this;
		} else {
			return new CollectionParser<X>(custom);
		}
	}

	@Override
	protected boolean parseAttribute(final Collection target, final Node item, final ParsingInfo<Collection> info) {
		return false;
	}

	@Override
	protected Collection newInstance(final ParsingInfo<Collection> info) {
		return new ArrayList<Object>();
	}

	@SuppressWarnings("unchecked")
	@Override
	protected boolean parseChildElement(final Collection list, final Element element, final ParsingInfo<Collection> info) {
		Object value = null;
		final String clazz = NodeNameInfo.getFullClassName(element, info.getStaticInfo());
		final Parser parser = clazz == null ? this.parser : Parser.createParser(clazz);
		value = parser.parse(info.createChild(parser, null, element));
		list.add(value);
		return true;
	}
}
